//IndicatorInstance
#pragma once

#include "stdafx.h"

#include <map>
#include <vector>
#include <deque>
#include <stdexcept>
#include <algorithm>
//<summary>
//	Base interface class for indicator 
//</summary>

namespace Indicator
{
	typedef enum _FXIndicatorType	
	{
		//Simple Moving Average
		SMA = 0,
		//Exponential Moving Average
		EMA = 1,
		//Weighted Moving Average
		WMA = 2,
		//Triangular Moving Average
		TMA = 3
	} FXIndicatorType;

	class IndicatorInstance 
	{
	public:
		IndicatorInstance(const FXInt symbol, const FXInt timeframe, const FXRateInfo* external_rates, const FXInt external_rates_size)
			throw(std::bad_alloc)
		{
			_symbol = symbol;
			_timeframe = timeframe;
			_rates = external_rates;
			_rates_size = external_rates_size;		

			_vecrates = std::deque<FXRateInfo>(external_rates, external_rates + external_rates_size);
			std::reverse(_vecrates.begin(), _vecrates.end());
		}

		virtual ~IndicatorInstance() { }
		
		void AddData(const FXRateInfo new_rate)
		{
			_vecrates.pop_back();
			_vecrates.push_front(new_rate);
		}		

		virtual FXDouble Calc(FXInt shift_back) = 0;

	protected:		
		const FXRateInfo* _rates;
		FXInt _rates_size;
		FXInt _symbol;
		FXInt _timeframe;
		std::deque<FXRateInfo> _vecrates;
	};

	class SMAIndicatorInstance : public IndicatorInstance
	{
	public:
		SMAIndicatorInstance(	const FXInt symbol, 
								const FXInt timeframe, 
								const FXRateInfo* rates, 
								const FXInt rates_size,  
								const FXInt period, 
								const FXInt shift):
		IndicatorInstance(symbol, timeframe, rates, rates_size)
		{
			_period = period;
			_shift = shift;
		}

		FXDouble Calc(FXInt shift_back)
		{
			//TODO: check for shift too big
			FXDouble sum = 0;
			for (FXInt i = shift_back + _shift; i < shift_back + _period + _shift; i++)
			{
				sum += _vecrates[i]._close;
			}

			return sum / _period;
		}

	private:
		FXInt _period;
		FXInt _shift;
	};

	

	class IndicatorHandler
	{
	public:
		//Initializes empty map with instance
		IndicatorHandler()
		{
			vec_handler = std::vector<IndicatorInstance*>();
			_indicator_id = 0; 
		}
		
		FXInt AddInstance(IndicatorInstance* new_indicator)
		{
			vec_handler.push_back(new_indicator);
			_indicator_id  = vec_handler.size();
			return _indicator_id;
		}

		void DeleteInstance(const FXInt indicator_id) throw (std::logic_error)
		{
			if (indicator_id < 0 || indicator_id >= vec_handler.size())
			{
				throw std::logic_error("Wrong indicator id");
			}
			 IndicatorInstance* to_remove = vec_handler[indicator_id];
			 delete to_remove;				
			 std::vector<IndicatorInstance*>::iterator erase_where = vec_handler.begin() + indicator_id;
			 vec_handler.erase(erase_where);
		}

		std::vector<IndicatorInstance*> vec_handler;

	private:
		FXInt _indicator_id;
	};
}